package com.plugin.appinit

import com.google.gson.Gson
import javassist.*
import org.gradle.api.Project

class ApplicationTransform {

  CtClass appCtClass
  ClassPool classPool
  Project mProject

  ArrayList<AppInitItem> pathList

  String contentField = "INIT_LIST"

  ApplicationTransform(Project project, CtClass ctClass,ArrayList<AppInitItem> pathList, ClassPool classPool) {
    this.appCtClass = ctClass
    this.classPool = classPool
    this.mProject = project
    this.pathList=pathList
  }

  void handleActivitySaveState() {
    mProject.logger.error(">>  ApplicationTransform ${appCtClass.name} ")
    //生成属性字段INIT_LIST
    String content = ""
    try {
      content = new Gson().toJson(pathList)
    } catch (Exception e) {
      e.printStackTrace()
    }
    mProject.logger.error(">>  ApplicationTransform initList : ${content}")
    generateEnabledField(appCtClass, content)
    //onCreate method
    CtMethod createCtMethod = appCtClass.declaredMethods.find {
      it.name == "onCreate" && it.parameterTypes == [] as CtClass[]
    }
    mProject.logger.error(">>  ApplicationTransform ${createCtMethod} ")
    if (createCtMethod == null) {//application 没有 onCreate 方法
      createCtMethod = CtNewMethod.make(generateActivityRestoreMethod(), appCtClass)
      appCtClass.addMethod(createCtMethod)
    }
    createCtMethod.insertBefore("com.appinit.lib.AppInitialManager.addInitList(INIT_LIST);\ncom.appinit.lib.AppInitialManager.onInit(this);\n")

    //attachBaseContext method
    CtClass contextCtClass=classPool.get("android.content.Context")
    def abctMParam=[contextCtClass] as CtClass[]
    assert abctMParam instanceof CtClass[]

    CtMethod attachBaseContextCtMethod=appCtClass.declaredMethods.find{
      it.name=="attachBaseContext" && it.parameterTypes==abctMParam
    }
    if(attachBaseContextCtMethod==null){
      attachBaseContextCtMethod=CtNewMethod.make(generateAttachBaseContextMethod(),appCtClass)
      appCtClass.addMethod(attachBaseContextCtMethod)
    }
    attachBaseContextCtMethod.insertBefore("com.appinit.lib.AppInitialManager.addInitList(INIT_LIST);\ncom.appinit.lib.AppInitialManager.attachBaseContext(this);\n")

    //onTerminate method
    CtMethod onTerminateCtMethod=appCtClass.declaredMethods.find{
      it.name=="onTerminate" && it.parameterTypes==[] as CtClass[]
    }
    if(onTerminateCtMethod==null){
      onTerminateCtMethod=CtNewMethod.make(generateOnTerminateCtMethod(),appCtClass)
      appCtClass.addMethod(onTerminateCtMethod)
    }
    onTerminateCtMethod.insertBefore("com.appinit.lib.AppInitialManager.onTerminate(this);\n")

    //onTrimMemory method
    def param=[CtClass.intType] as CtClass[]
    assert param instanceof CtClass[]
    CtMethod onTrimMemoryCtMethod=appCtClass.declaredMethods.find{
      it.name=="onTrimMemory" && it.parameterTypes==param
    }
    if(onTrimMemoryCtMethod==null){
      onTrimMemoryCtMethod=new CtMethod(CtClass.voidType,"onTrimMemory",param,appCtClass)
      onTrimMemoryCtMethod.setModifiers(Modifier.PUBLIC)
      onTrimMemoryCtMethod.setBody("{ com.appinit.lib.AppInitialManager.onTrimMemory(this,\$1);\nsuper.onTrimMemory(\$1); }")
      appCtClass.addMethod(onTrimMemoryCtMethod)
    }else{
      onTrimMemoryCtMethod.insertBefore("com.appinit.lib.AppInitialManager.onTrimMemory(this,\$1);\n")
    }
  }

  void generateEnabledField(CtClass ctClass, String path) {
    CtField pathCtField = ctClass.declaredFields.find {
      it.name == contentField && it.getType().name == "java.lang.String"
    }
    if (pathCtField != null) {
      ctClass.removeField(pathCtField)
    }
    pathCtField = new CtField(classPool.get("java.lang.String"), contentField, ctClass)
    pathCtField.setModifiers(Modifier.PRIVATE | Modifier.STATIC |Modifier.FINAL)
    ctClass.addField(pathCtField, CtField.Initializer.constant(path))
  }

  static String generateActivityRestoreMethod() {
    StringBuilder stringBuilder = new StringBuilder()
    stringBuilder.append("public void onCreate() {\n ")
    stringBuilder.append("super.onCreate();\n")
    stringBuilder.append("}")
    return stringBuilder.toString()
  }

  static String generateAttachBaseContextMethod() {
    StringBuilder stringBuilder = new StringBuilder()
    stringBuilder.append("protected void attachBaseContext(android.content.Context base) {\n ")
    stringBuilder.append("super.attachBaseContext(base);\n")
    stringBuilder.append("}")
    return stringBuilder.toString()
  }

  static String generateOnTerminateCtMethod() {
    StringBuilder stringBuilder = new StringBuilder()
    stringBuilder.append("public void onTerminate() {\n ")
    stringBuilder.append("super.onTerminate();\n")
    stringBuilder.append("}")
    return stringBuilder.toString()
  }

}
